package com.xiaoxx.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.lang.reflect.Method;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @Author HX
 * @Date 2022/6/10 9:51
 */
@Configuration
@EnableAsync
@Slf4j
public class ThreadToolConfig implements AsyncConfigurer {

    @Bean("myThreadPool")
    public ThreadPoolTaskExecutor myThreadPool() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        int i = Runtime.getRuntime().availableProcessors();//获取到服务器的cpu内核
        //核心线程数
        executor.setCorePoolSize(i);
        //最大线程数
        executor.setMaxPoolSize(i*2);
        //最大存活时间 5分钟
        executor.setKeepAliveSeconds(60 * 5);
        //线程池名称前缀
        executor.setThreadNamePrefix("pool-thread-");
        //拒绝策略
        //ThreadPoolExecutor.AbortPolicy 默认策略  直接抛出java.util.concurrent.RejectedExecutionException异常
        //ThreadPoolExecutor.DiscardPolicy  放弃当前任务，并且不会抛出任何异常
        //ThreadPoolExecutor.DiscardOldestPolicy 会将队列中最早添加的元素移除，再尝试添加，如果失败则按该策略不断重试
        //ThreadPoolExecutor.CallerRunsPolicy 由调用线程（提交任务的线程）处理该任务，如果调用线程是主线程，那么主线程会调用执行器中的execute方法来执行该任务
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //阻塞队列大小
        executor.setQueueCapacity(10);
        executor.initialize();
        return executor;
    }

    /**
     * 异常处理
     *
     * @return
     */
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new CustomAsyncExceptionHandler();
    }

    /**
     * 自定义异常处理类
     */
    static class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
        @Override
        public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {
            log.error("==========================" + throwable.getMessage() + "=======================", throwable);
            log.error("exception method:" + method.getName());
            for (Object param : obj) {
                log.error("Parameter value - " + param);
            }
        }
    }
}
